home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / BBS-Archive / Comm / AmiTCP30b2.lha / src / devs / agnet / agnet.c < prev    next >
C/C++ Source or Header  |  1994-02-25  |  22KB  |  892 lines

  1. RCS_ID_C="$Id: agnet.c,v 4.8 1994/02/25 01:13:12 ppessi Exp $";
  2. /*
  3.  * agnet.c --- agnet main program and arexx interface
  4.  *
  5.  * Author: ppessi <Pekka.Pessi@hut.fi>
  6.  *
  7.  * Copyright (c) 1993 OHT-AmiTCP/IP Group,
  8.  *                    Helsinki University of Technology, Finland.
  9.  *                    All rights reserved.
  10.  *
  11.  * Created      : Sat Feb 20 18:30:59 1993 ppessi
  12.  * Last modified: Thu Oct  7 18:23:33 1993 ppessi
  13.  *
  14.  * $Log: agnet.c,v $
  15.  * Revision 4.8  1994/02/25  01:13:12  ppessi
  16.  * *** empty log message ***
  17.  *
  18.  * Revision 3.1  93/10/07  19:24:08  ppessi
  19.  * Release 2.1 version
  20.  * 
  21.  * Revision 2.1  93/05/14  16:46:32  ppessi
  22.  * Release version.
  23.  * 
  24.  * Revision 2.0  93/03/10  16:35:03 16:35:03  ppessi (Pekka Pessi)
  25.  * Prototype release.
  26.  */
  27.  
  28. #include <string.h>
  29. #include <stdarg.h>
  30.  
  31. #include <dos/dostags.h>
  32. #include <dos/rdargs.h>
  33. #include <intuition/intuition.h>
  34. #include <rexx/storage.h>
  35. #include <rexx/rxslib.h>
  36.  
  37. #include <clib/exec_protos.h>
  38. #include <clib/dos_protos.h>
  39. #include <clib/utility_protos.h>
  40. #include <clib/intuition_protos.h>
  41.  
  42. #ifdef __SASC
  43. #include <pragmas/exec_sysbase_pragmas.h>
  44. #include <pragmas/dos_pragmas.h>
  45. #include <pragmas/utility_pragmas.h>
  46. #include <pragmas/intuition_pragmas.h>
  47. #endif
  48.  
  49. #include "agnet.h"
  50. #include "agnet_protos.h"
  51. #include "agnet_rev.h"
  52. #include "bases.h"
  53.  
  54. static ULONG init_arexx(VOID);
  55. static VOID poll_arexx(VOID);
  56. static VOID deinit_arexx(VOID);
  57.  
  58. /*
  59.  * We start as a CLI.
  60.  * Assembler stub routine does a MakeLibrary and
  61.  * initializes needed librarybases
  62.  */
  63. LONG ASM main(REG(a6)struct AgnetDevice *adb)
  64. {
  65.   struct Process *proc;
  66.   struct IOSana2Req *io;
  67.   ULONG waitmask, rexxsignal, signals;
  68.   UBYTE devsignal;
  69.   UBYTE myname[sizeof(AGNETDEVNAME)+5];
  70.  
  71.   AgnetDeviceBase = adb;
  72.  
  73.   proc = (struct Process *)FindTask(0L);
  74.  
  75.   /* Initialize the device base */
  76.   adb->ad_Device.lib_Node.ln_Pri  = AGNET_DEV_PRI;
  77.   adb->ad_Device.lib_Node.ln_Type = NT_DEVICE;
  78.   adb->ad_Device.lib_Node.ln_Name = myname;
  79.   adb->ad_Device.lib_Version  = VERSION;
  80.   adb->ad_Device.lib_Revision = REVISION;
  81.   adb->ad_Device.lib_IdString = VSTRING;
  82.   adb->ad_Task = (struct Task *)proc;
  83.  
  84.   /* Set up our unit message port */
  85.   /* Attempt to allocate a signal bit for our Unit MsgPort. */
  86.   devsignal = AllocSignal(-1L);
  87.   if (devsignal == -1) {
  88.     return 20;
  89.   }
  90.   NewList(&adb->ad_MsgPort.mp_MsgList);
  91.   adb->ad_MsgPort.mp_SigBit = devsignal;
  92.   adb->ad_MsgPort.mp_SigTask = (struct Task *)proc;
  93.   adb->ad_MsgPort.mp_Flags = PA_SIGNAL;
  94.  
  95.   /* Initialize our device base semafore */
  96.   InitSemaphore(&adb->ad_Lock);
  97.  
  98.   InitLRandom();
  99.  
  100. #ifdef AGREXX
  101.   /* Initialize Arexx port */
  102.   rexxsignal = init_arexx();
  103. #else
  104.   rexxsignal = 0;
  105. #endif
  106.   /* OK, we are ready to add agnet.device to system */
  107.   {
  108.     int i, n = sizeof(AGNETDEVNAME) - 1;
  109.     strcpy(myname, AGNETDEVNAME);
  110.  
  111.     Forbid();
  112.     for (i = 0; i < 9; i++) {
  113.       if (!FindName(&adb->ad_SysBase->DeviceList, myname))
  114.     break;
  115.       myname[n] = '.'; myname[n+1] = '1' + i; myname[n+2] = '\0';
  116.     }
  117.     AddDevice(adb);
  118.     Permit();
  119.   }
  120.  
  121.   waitmask = (1<<devsignal) | rexxsignal | SIGBREAKF_CTRL_F ;
  122.  
  123.   while (TRUE) {
  124.     signals = Wait(waitmask);    /* wait for device command */
  125.  
  126.     if (signals & SIGBREAKF_CTRL_F) {
  127.       if (DoExpunge(adb))
  128.     break;
  129.     }
  130.  
  131.     while (io = (struct IOSana2Req *)GetMsg(&adb->ad_MsgPort)) 
  132.       PerformIO(io);
  133.  
  134. #ifdef AGREXX
  135.     if (signals & rexxsignal)
  136.       poll_arexx();
  137. #endif
  138.   }
  139.  
  140.   /* Clean up */
  141. #ifdef AGREXX
  142.   deinit_arexx();
  143. #endif
  144.   FreeSignal(devsignal);
  145.   return 0;
  146. }
  147.  
  148. /* Local prototypes */
  149. static LONG ParseConfig(struct AgnetDevUnit *, struct RDArgs *, STRPTR*);
  150. static BOOL GetBitAddress(UBYTE *addr, UBYTE *string, LONG bitsize);
  151. static char *SanaSprintf(register char *ap, int len);
  152. static ULONG csprintf(struct CSource *buf, const char *fmt, ...);
  153.  
  154. #define CONFIG_ENV_TEMPLATE "ENV:SANA2/config%ld.agnet"
  155.  
  156. #define UNINITIALIZED 0xffffffff
  157.  
  158. /*
  159.  *  ReadConfig
  160.  *
  161.  *  Attempt to read in the driver's configuration file.
  162.  *
  163.  *  The files are named by ENV:SANA2/agnet%d.config where %d is the decimal
  164.  *  representation of the device's unit number.
  165.  *
  166.  *  Return FALSE upon error.
  167.  */
  168. BOOL ReadConfig(struct AgnetDevUnit *adu)
  169. {
  170.   UBYTE *fbuf = NULL;
  171.   UBYTE buff[40];
  172.   struct CSource csbuff = { NULL, sizeof(buff), 0L };
  173.   BPTR ConfigFile;
  174.   LONG offset, len;
  175.   BOOL ok = FALSE;
  176.  
  177.   csbuff.CS_Buffer = buff;
  178.  
  179.   /* This configures unit by default values */
  180.   adu->adu_HardwareType = UNINITIALIZED;
  181.  
  182.   /* Create the name of our config file.. */
  183.   csprintf(&csbuff, CONFIG_ENV_TEMPLATE, (ULONG)adu->adu_UnitNum);
  184.  
  185.   /* ...and open it. */
  186.   ConfigFile = Open(buff, MODE_OLDFILE);
  187.   if (!ConfigFile) 
  188.     return TRUE;
  189.  
  190.   len = (Seek(ConfigFile, 0L, 1), Seek(ConfigFile, 0L, 0));
  191.   if (len >= 0 && (fbuf = AllocMem(len+2, MEMF_PUBLIC))) {
  192.     Seek(ConfigFile, 0L, -1);
  193.     if (Read(ConfigFile, fbuf, len) == len) {
  194.       ok = TRUE;
  195.       fbuf[len] = '\n';
  196.       fbuf[len+1] = '\0';
  197.     } 
  198.   }
  199.   Close(ConfigFile);
  200.  
  201.   if (ok) { 
  202.     struct RDArgs *rdargs = AllocDosObject(DOS_RDARGS, NULL);
  203.     STRPTR *errmsg;
  204.  
  205.     if (rdargs) {
  206.       /* Remove Comment lines */ 
  207.       for (offset = 0; offset < len;) {
  208.     if (fbuf[offset] == '#')
  209.       while(fbuf[offset] != '\n')
  210.         fbuf[offset++] = ' ';
  211.     else
  212.       while(fbuf[offset++] != '\n');
  213.     fbuf[offset - 1] = ' '; /* remove linefeeds in file */
  214.       }
  215.       /* Add sentinel */
  216.       fbuf[len] = '\n';
  217.  
  218.       rdargs->RDA_Source.CS_Buffer = fbuf;
  219.       rdargs->RDA_Source.CS_Length = len + 1;
  220.       rdargs->RDA_Source.CS_CurChr = 0;
  221.  
  222.       if (ParseConfig(adu, rdargs, &errmsg)) {
  223.     struct EasyStruct es;
  224.     APTR args[2];
  225.     args[0] = errmsg;
  226.     args[1] = buff;
  227.     es.es_StructSize = sizeof(es);
  228.     es.es_Flags = 0;
  229.     es.es_Title = AGNETDEVNAME;
  230.     es.es_TextFormat="Error %s in \nthe configuration file\n%s";
  231.     es.es_GadgetFormat="Okay";
  232.     EasyRequestArgs(NULL, &es, 0, args);
  233.     ok = FALSE;
  234.       }
  235.     }
  236.     FreeDosObject(DOS_RDARGS, rdargs);
  237.   }
  238.  
  239.   if (fbuf) FreeMem(fbuf, len+2);
  240.   return ok;
  241. }
  242.  
  243. #define MYREXXNAME "agnet"
  244. #define MYREXXEXTENSION "agnet"
  245.  
  246. /* Error strings */
  247. #define ERR_MALFORMED "Malformed command line"
  248. #define ERR_SYNTAX    "Syntax error"
  249. #define ERR_WIRE      "Illegal wiretype"
  250. #define ERR_ADDRESS   "Illegal address"
  251. #define ERR_UNIT      "Illegal unit number"
  252. #define ERR_INITUNIT  "Error initializing unit"
  253. #define ERR_MEMORY    "Memory exhausted"
  254. #define ERR_OPEN      "Unit is currently opened"
  255. #define ERR_VALUE     "Illegal value"
  256.  
  257. #ifdef AGREXX
  258. /*
  259.  * Arexx interface functions to agnet.device 
  260.  */
  261.  
  262. #include    <rexx/storage.h>
  263. #include    <rexx/rxslib.h>
  264. #include        <clib/rexxsyslib_protos.h>
  265. #ifdef __SASC
  266. #include    <pragmas/rexxsyslib_pragmas.h>
  267. #endif
  268. #include    "SimpleRexx.h"
  269.  
  270. AREXXCONTEXT    RexxContext;
  271.  
  272. static LONG ParseRexx(UBYTE *arg, UBYTE **errstr, UBYTE **result);
  273. static LONG ParseQuery(struct AgnetDevUnit *, struct RDArgs *,
  274.                STRPTR *,STRPTR *);
  275. /*
  276.  * Initialize Arexx port
  277.  */
  278. static ULONG 
  279. init_arexx(VOID)
  280. {
  281.   ULONG rexxsignal;
  282.  
  283.   RexxContext = InitARexx(MYREXXNAME, MYREXXEXTENSION);
  284.  
  285.   if (!RexxContext)
  286.     return 0L;
  287.  
  288.   rexxsignal = ARexxSignal(RexxContext);
  289.  
  290.   return rexxsignal;
  291. }
  292.  
  293. /* 
  294.  * Free ARexx port
  295.  */
  296. static VOID 
  297. deinit_arexx(VOID)
  298. {
  299.   if (RexxContext)
  300.     FreeARexx(RexxContext);
  301. }
  302.  
  303. /* 
  304.  * Poll Arexx port
  305.  */
  306. static VOID 
  307. poll_arexx(VOID)
  308. {
  309.   struct RexxMsg *rmsg;
  310.  
  311.   /*
  312.    * Process the ARexx messages...
  313.    */
  314.   while (rmsg = GetARexxMsg(RexxContext)) {
  315.     UBYTE *error = NULL, *result = NULL;
  316.     LONG errlevel=0;
  317.  
  318.     if (errlevel = ParseRexx(ARG0(rmsg), &error, &result)) {
  319.       SetARexxLastError(RexxContext, rmsg, error);
  320.     }
  321.     ReplyARexxMsg(RexxContext, rmsg, result, errlevel);
  322.   }
  323. }
  324.  
  325. /*
  326.  * Rexx commands
  327.  */
  328.  
  329. #define REXXKEYWORDS "U=UNIT,Q=QUERY,E=EXIT=EXPUNGE"
  330. #define KEYWORDLEN  16
  331.  
  332. #define KEY_UNIT 0
  333. #define KEY_QUERY 1
  334. #define KEY_EXIT 2
  335.  
  336. /*
  337.  * Parse the ARexx command 
  338.  */
  339. static LONG
  340. ParseRexx(UBYTE *arg, UBYTE **errstr, UBYTE **result)
  341. {
  342.   struct AgnetDevice *adb = AgnetDeviceBase;
  343.   LONG errlevel = 0;
  344.   UBYTE Buffer[KEYWORDLEN];
  345.   LONG len = LengthArgstring(arg) + 2;
  346.   UBYTE *cmd = AllocMem(len, 0);
  347.   struct RDArgs *rdargs = AllocDosObject(DOS_RDARGS, NULL);
  348.   LONG unit, keyword;
  349.   struct AgnetDevUnit *adu;
  350.  
  351.   if (!cmd || !rdargs) {
  352.     errlevel = 40;
  353.     *errstr = ERR_MEMORY;
  354.   } else {
  355.     memcpy(cmd, arg, len - 2);
  356.     /* Add sentinel */
  357.     cmd[len-2] = '\n'; cmd[len-1] = '\0';
  358.     rdargs->RDA_Source.CS_Buffer = cmd;
  359.     rdargs->RDA_Source.CS_Length = len - 1;
  360.     rdargs->RDA_Source.CS_CurChr = 0;
  361.     /* First, parse the command keyword */
  362.     if (ReadItem(Buffer, sizeof(Buffer), &rdargs->RDA_Source) <= 0 ||
  363.     (keyword = FindArg(REXXKEYWORDS, Buffer)) < 0) {
  364.       errlevel = 20;
  365.       *errstr = ERR_MALFORMED;
  366.     } else {
  367.       switch (keyword) {
  368.       case KEY_UNIT:
  369.       case KEY_QUERY:
  370.     /* Parse unit number */
  371.     if ((len = StrToLong(cmd + rdargs->RDA_Source.CS_CurChr, &unit)) < 0 ||
  372.         unit >= AD_MAXUNITS) {
  373.       errlevel = 20;
  374.       *errstr = ERR_UNIT;
  375.       break;
  376.     }
  377.     rdargs->RDA_Source.CS_CurChr += len;
  378.  
  379.     if (!(adu = adb->ad_Units[unit])) 
  380.       /* If there is no opened unit, we init one */
  381.       if (keyword == KEY_QUERY || !(adu = InitUnit(unit))) {
  382.         /* We got no unit structure, there was an initialization
  383.            problem, we must give up */
  384.         *errstr = ERR_INITUNIT;
  385.         errlevel = 20;
  386.         break;
  387.       }
  388.     if (keyword == KEY_UNIT) {
  389.       /* Parse the rest of the line with ParseConfig */
  390.       errlevel = ParseConfig(adu, rdargs, errstr);
  391.       break;
  392.     } else {
  393.       errlevel = ParseQuery(adb->ad_Units[unit], rdargs, errstr, result);
  394.       break;
  395.     }
  396.       case KEY_EXIT:
  397.     /* We try to expunge */
  398.     SetSignal(SIGBREAKF_CTRL_F, SIGBREAKF_CTRL_F);
  399.     break;
  400.       }
  401.     } 
  402.   } 
  403.     
  404.   if (cmd) FreeMem(cmd, len);
  405.   if (rdargs) FreeDosObject(DOS_RDARGS, rdargs);
  406.  
  407.   return errlevel;
  408. }
  409. #endif /* AGREXX */
  410.  
  411. /* 
  412.  * Configuration parameters
  413.  */
  414. #define CONFIG_ARGS              20    /* # of args in CONFIG_TEMPLATE */
  415. #define CONFIG_TEMPLATE "WIRE/K" \
  416.   ",MTU/N/K,MINTU/N/K,BPS/N/K,ADDR=ADDRESS/K" \
  417.   ",DELAY/N/K,DEV=DEVIATION/N/K,ERRORS/K/N,LOSS/K/N,DST=DSTUNIT/N"
  418.  
  419. #define CMD_WIRE      0
  420. #define CMD_MTU       1    /* Maximum transfer unit */
  421. #define CMD_MINTU     2    /* Minimum Trransfer unit */
  422. #define CMD_BPS       3    /* Bits per second */
  423. #define CMD_ADDR      4    /* Address string */
  424. #define CMD_DELAY     5    /* Delay in ms */
  425. #define CMD_DEVIATION 6    /* Deviation in ms */
  426. #define CMD_ERRORS    7 /* Bit error probability */
  427. #define CMD_LOSS      8    /* Packet loss probability */
  428. #define CMD_PPUNIT    9    /* Destination unit */
  429.  
  430. #define CMD_ALL      10 /* All values queried */
  431.                
  432. #define WIRE_TEMPLATE   "LOOPBACK,ETHERNET,IEEE802,ARCNET" \
  433.   ",LOCALTALK,AMOKNET" \
  434.   ",PPP,SLIP,CSLIP" \
  435.  
  436. #define WIRE_LOOPBACK  0
  437. #define WIRE_ETHERNET  1
  438. #define WIRE_IEEE802   2
  439. #define WIRE_ARCNET    3
  440. #define WIRE_LOCALTALK 4
  441. #define WIRE_AMOKNET   5
  442. #define WIRE_PPP       6
  443. #define WIRE_SLIP      7
  444. #define WIRE_CSLIP     8
  445.  
  446. #ifdef AGREXX
  447. #include <exec/initializers.h>
  448.  
  449. #define MAXQUERYLEN 512
  450.  
  451. #define QUERY_TEMPLATE "WIRE/S" \
  452.   ",MTU/S,MINTU/S,BPS/S,ADDR=ADDRESS/S" \
  453.   ",DELAY/S,DEV=DEVIATION/S,ERRORS/S,LOSS/S,DST=DSTUNIT/S,ALL/S"
  454.  
  455. static struct {
  456.   STRPTR title;
  457.   WORD offset;
  458.   enum { nulong, wire, address } type;
  459. } query_titles[] = {
  460.   { "WIRE",     OFFSET(AgnetDevUnit, adu_HardwareType), wire },
  461.   { "MTU",      OFFSET(AgnetDevUnit, adu_MaxTU),        nulong },
  462.   { "MINTU",    OFFSET(AgnetDevUnit, adu_MinTU),        nulong },
  463.   { "BPS",      OFFSET(AgnetDevUnit, adu_BPS),          nulong },
  464.   { "ADDRESS",  OFFSET(AgnetDevUnit, adu_Addr),         address },
  465.   { "DELAY",    OFFSET(AgnetDevUnit, adu_Delay),        nulong },
  466.   { "DEVIATION",OFFSET(AgnetDevUnit, adu_Deviation),    nulong },
  467.   { "ERRORS",   OFFSET(AgnetDevUnit, adu_Errors),       nulong },
  468.   { "LOSS",     OFFSET(AgnetDevUnit, adu_Loss),         nulong },
  469.   { "DSTUNIT",  OFFSET(AgnetDevUnit, adu_PPUnit),       nulong }
  470. };
  471.  
  472. #define AT_OFFSET(X,Y) ((UBYTE *)X + Y)
  473. #define ULONG_AT(X,Y) (*(ULONG*)AT_OFFSET(X,Y))
  474.  
  475. static struct {
  476.   ULONG  type;
  477.   STRPTR name;
  478. } wirenames[] = {
  479.   { S2WireType_LoopBack,  "Loopback" },
  480.   { S2WireType_Ethernet,  "Ethernet" },
  481.   { S2WireType_IEEE802,   "IEEE802" },
  482.   { S2WireType_Arcnet,    "Arcnet" },
  483.   { S2WireType_LocalTalk, "LocalTalk" },
  484.   { S2WireType_AmokNet,   "AmokNet" },
  485.   { S2WireType_PPP,       "PPP" },
  486.   { S2WireType_SLIP,      "SLIP" },
  487.   { S2WireType_CSLIP,     "CSLIP" },
  488.   { S2WireType_LoopBack,  "Unknown" }
  489. };
  490. #endif
  491.  
  492. /*
  493.  * Parse a configuration command
  494.  * adu = NULL if parse an ARexx command
  495.  * return differs from zero if an error
  496.  */
  497. static LONG 
  498. ParseConfig(struct AgnetDevUnit *adu, struct RDArgs *rdargs, 
  499.         STRPTR *errormessage)
  500. {
  501.   LONG args[CONFIG_ARGS] = {0};
  502.   LONG error; 
  503.   LONG ppunit;
  504.   UBYTE address[MAX_ADDR_BYTES] = {0};
  505.   UWORD addrfieldsize;
  506.   ULONG hardwaretype, maxtu, mintu, bps, delay, deviation, errors, loss;
  507.   BOOL virgin;
  508.   LONG wire;
  509.  
  510.   /* Parse the file or the line...*/
  511.   rdargs = ReadArgs(CONFIG_TEMPLATE, args, rdargs);
  512.   if (error = !rdargs) {
  513.     if (errormessage)
  514.       *errormessage = ERR_SYNTAX;
  515.     return error;
  516.   }
  517.  
  518.   hardwaretype = adu->adu_HardwareType;
  519.   addrfieldsize = adu->adu_AddrFieldSize;
  520.   ppunit = adu->adu_PPUnit;
  521.   maxtu = adu->adu_MaxTU;
  522.   mintu = adu->adu_MinTU;
  523.   bps   = adu->adu_BPS;
  524.   delay = adu->adu_Delay;
  525.   deviation = adu->adu_Deviation;
  526.   errors    = adu->adu_Errors;
  527.   loss      = adu->adu_Loss ;
  528.   memcpy(address, adu->adu_Addr, MAX_ADDR_BYTES);
  529.  
  530.   virgin = hardwaretype == UNINITIALIZED;
  531.  
  532.   if (args[CMD_WIRE]) {
  533.     wire = FindArg(WIRE_TEMPLATE, args[CMD_WIRE]);
  534.   } else if (virgin) {
  535.     wire = S2WireType_Ethernet;
  536.   }
  537.  
  538.   if (args[CMD_WIRE] || virgin) {
  539.     switch (wire) {
  540.     case WIRE_LOOPBACK:
  541.       /* This is simple loopback type */
  542.       hardwaretype = S2WireType_LoopBack;
  543.       addrfieldsize = 0;    /* No addresses */
  544.       maxtu = 1024;
  545.       bps   = 100000000;    /* it's fast like a hell...*/
  546.       mintu = 0;
  547.       /* There is no need for address but we zero it anyways */
  548.       memset(address, 0, MAX_ADDR_BYTES);
  549.       break;
  550.  
  551.     case WIRE_ETHERNET:
  552.       /* This is default */
  553.       hardwaretype = S2WireType_Ethernet;
  554.       addrfieldsize = 48;
  555.       maxtu = 1500;
  556.       bps   = 10000000;        /* 10 Mb/s */
  557.       mintu = 1;
  558.       /* Ethernet address is same as unit number */
  559.       memset(address + 6, 0, MAX_ADDR_BYTES-2);
  560.       memcpy(address, "ETHER", 5);
  561.       address[5] = adu->adu_UnitNum;
  562.       ppunit = -1;
  563.       break;
  564.  
  565.     case WIRE_IEEE802:
  566.       /* Wiretype is IEEE802 */
  567.       hardwaretype  = S2WireType_IEEE802;
  568.       addrfieldsize = 48;
  569.       maxtu = 1500;
  570.       bps   = 10000000;        /* 10 Mb/s */
  571.       mintu = 1;
  572.       /* IEEE802 address is same as unit number */
  573.       memset(address+6, 0, MAX_ADDR_BYTES-6);
  574.       memcpy(address, "IEEE8", 5);
  575.       address[5] = adu->adu_UnitNum;
  576.       ppunit = -1;
  577.       break;
  578.  
  579.     case WIRE_ARCNET:
  580.       hardwaretype  = S2WireType_Arcnet;
  581.       addrfieldsize = 8;
  582.       maxtu = 506;
  583.       bps   = 5000000L;        /* 5 Mb/s */
  584.       mintu = 1;
  585.       /* Arcnet address is got from unit number */
  586.       memset(adu->adu_Addr, 0, MAX_ADDR_BYTES);
  587.       adu->adu_Addr[0] = 255 - adu->adu_UnitNum;
  588.       ppunit = -1;
  589.       break;
  590.  
  591.     case WIRE_LOCALTALK:
  592.       /* Don't know much, but... */
  593.       hardwaretype  = S2WireType_LocalTalk;
  594.       addrfieldsize = 8;
  595.       maxtu = 256;
  596.       bps   = 128000L;        /* 128 kb/s */
  597.       mintu = 1;
  598.       /* Localnet address is got from unit number */
  599.       memset(address, 0, MAX_ADDR_BYTES);
  600.       address[0] = adu->adu_UnitNum;
  601.       ppunit = -1;
  602.       break;
  603.  
  604.       /* Amoknet parameters are all got with RaHi method */
  605.     case WIRE_AMOKNET:
  606.       /* Don't know much, but... */
  607.       hardwaretype  = S2WireType_AmokNet;
  608.       addrfieldsize = 8;
  609.       maxtu = 512;
  610.       bps   = 128000L;        /* 128 kb/s */
  611.       mintu = 1;
  612.       /* Amoknet address is got from unit number */
  613.       memset(address, 0, MAX_ADDR_BYTES);
  614.       address[0] = adu->adu_UnitNum;
  615.       break;
  616.  
  617.     case WIRE_PPP:
  618.       hardwaretype = S2WireType_PPP; goto serials;
  619.     case WIRE_SLIP:
  620.       hardwaretype = S2WireType_SLIP; goto serials;
  621.     case WIRE_CSLIP:
  622.       hardwaretype = S2WireType_CSLIP; 
  623.     serials: 
  624.       addrfieldsize = 32;
  625.       maxtu = 1006;
  626.       bps   = 9600L;        /* 9600 b/s */
  627.       mintu = 1;
  628.       /* SLIP address is set during config */
  629.       memset(address, 0, MAX_ADDR_BYTES);
  630.       break;
  631.     default:
  632.       if (errormessage)
  633.     *errormessage = ERR_WIRE;
  634.       error = 5;
  635.       goto free_and_exit;
  636.     }
  637.   }
  638.   if (args[CMD_MTU]) {
  639.     maxtu = *(ULONG *)args[CMD_MTU];
  640.   }
  641.  
  642.   if (args[CMD_MINTU]) {
  643.     mintu = *(ULONG *)args[CMD_MINTU];
  644.   }
  645.  
  646.   if (args[CMD_BPS]) {
  647.     bps = *(ULONG *)args[CMD_BPS];
  648.   }
  649.  
  650.   if (args[CMD_ADDR]) {
  651.     memset(address, 0, MAX_ADDR_BYTES);
  652.     if (!GetBitAddress(address, (UBYTE *)args[CMD_ADDR], addrfieldsize)) {
  653.       if (errormessage)
  654.     *errormessage = ERR_ADDRESS;
  655.       error = 7;
  656.       goto free_and_exit;
  657.     }
  658.   }
  659.  
  660.   if (args[CMD_DELAY]) {
  661.     delay = *(ULONG *)args[CMD_DELAY];
  662.     /* maximum delay is 0x800000 ms, that is fairly over an hour */
  663.     if (delay >= 0x800000)
  664.       delay = 0x7fffff;
  665.   }
  666.  
  667.   if (args[CMD_DEVIATION]) {
  668.     deviation = *(ULONG *)args[CMD_DEVIATION];
  669.   }
  670.  
  671.   if (args[CMD_ERRORS]) {
  672.     errors = *(ULONG *)args[CMD_ERRORS];
  673.     if (errors > ERRORS_MAX) {
  674.       error = 5;
  675.       *errormessage = ERR_VALUE;
  676.       goto free_and_exit;
  677.     }
  678.   }
  679.  
  680.   if (args[CMD_LOSS]) {
  681.     loss = *(ULONG *)args[CMD_LOSS];
  682.     if (loss > LOSS_MAX) {
  683.       error = 5;
  684.       *errormessage = ERR_VALUE;
  685.       goto free_and_exit;
  686.     }
  687.   }
  688.  
  689.   if (args[CMD_PPUNIT]) {
  690.     ppunit = *(ULONG *)args[CMD_PPUNIT];
  691.   }
  692.  
  693.   if (!virgin) {
  694.     LockUnit(adu);
  695.     /* 
  696.      * Changing the hardware type or reducing the MTU requires 
  697.      * that the unit is not currently open
  698.      */
  699.     if ((adu->adu_HardwareType != hardwaretype ||
  700.      adu->adu_MaxTU > maxtu) &&
  701.     adu->adu_Unit.unit_OpenCnt != 0 ) {
  702.       UnlockUnit(adu);
  703.       error = 5;
  704.       *errormessage = ERR_OPEN;
  705.       goto free_and_exit;
  706.     }
  707.   }
  708.  
  709.   adu->adu_HardwareType = hardwaretype;
  710.   adu->adu_AddrFieldSize = addrfieldsize;
  711.   adu->adu_PPUnit = ppunit;
  712.   adu->adu_MinTU = mintu;
  713.   adu->adu_BPS   = bps;
  714.   adu->adu_Delay = delay;
  715.   adu->adu_Deviation = deviation;
  716.   adu->adu_Errors = errors;
  717.   adu->adu_Loss  = loss;
  718.   memcpy(adu->adu_Addr, address, MAX_ADDR_BYTES);
  719.  
  720.   /*
  721.    * Enlarging the MTU requires offlining the device temporarily
  722.    */
  723.   if (!virgin && adu->adu_MaxTU < maxtu) {
  724.     DoOffline(adu);
  725.     adu->adu_MaxTU = maxtu;
  726.     DoOnline(adu);
  727.   } else {
  728.     adu->adu_MaxTU = maxtu;
  729.   }
  730.  
  731.   if (!virgin)
  732.     UnlockUnit(adu);
  733.  
  734.  free_and_exit:
  735.   if (rdargs) 
  736.     FreeArgs(rdargs);
  737.   return error;
  738. }
  739.  
  740. #ifdef AGREXX
  741. /*
  742.  * Parse Query Command
  743.  */
  744. static LONG
  745. ParseQuery(struct AgnetDevUnit *adu, 
  746.        struct RDArgs *rdargs,
  747.        STRPTR *errstr,
  748.        STRPTR *result)
  749. {
  750.   LONG errlevel = 0;
  751.   LONG args[CONFIG_ARGS] = {0};
  752.   char res[MAXQUERYLEN];
  753.   struct CSource csres = { NULL, sizeof(res), 0L };
  754.   BOOL all;
  755.   LONG i;
  756.  
  757.   csres.CS_Buffer = res;
  758.  
  759.   /* Parse the file or the line...*/
  760.   rdargs = ReadArgs(QUERY_TEMPLATE, args, rdargs);
  761.   if (errlevel = !rdargs) {
  762.     *errstr = ERR_SYNTAX;
  763.     return errlevel;
  764.   }
  765.  
  766.   all = args[CMD_ALL];
  767.   for (i = CMD_WIRE; i < CMD_ALL; i++) 
  768.     if (all || args[i]) {
  769.       if (csres.CS_CurChr != 0 && csres.CS_CurChr < csres.CS_Length) 
  770.     res[csres.CS_CurChr++] = ' ';
  771.       switch (query_titles[i].type) {
  772.       case nulong:
  773.     csprintf(&csres, "%s=%ld", query_titles[i].title, 
  774.                ULONG_AT(adu, query_titles[i].offset));
  775.     break;
  776.  
  777.       case wire:
  778.     {
  779.       int j; int type = ULONG_AT(adu, query_titles[i].offset);
  780.       for (j = 0; j < sizeof(wirenames)/sizeof(wirenames[0]) - 2; j++) 
  781.         if (wirenames[j].type == type) 
  782.           break;
  783.       csprintf(&csres, "%s=%s", query_titles[i].title, 
  784.           wirenames[j].name);
  785.     }
  786.     break;
  787.  
  788.       case address:
  789.     csprintf(&csres, "%s=%s", query_titles[i].title, 
  790.         SanaSprintf(AT_OFFSET(adu,query_titles[i].offset),
  791.                 adu->adu_AddrFieldSize + 7 >> 3));
  792.     break;
  793.       }
  794.     }
  795.  
  796.   *result = CreateArgstring(res, csres.CS_CurChr);
  797.   if (!*result) {
  798.     *errstr = ERR_MEMORY;
  799.     return 40;
  800.   }
  801.   return errlevel;
  802. }
  803.  
  804. #endif /* AGREXX */
  805.  
  806. /*
  807.  * Read hexadecimal address string into array.
  808.  *
  809.  * UBYTE *addr     = address array
  810.  * UBYTE *string   = hexadecimal address string, 
  811.  *                   each byte sparated by colon (":")
  812.  * LONG   bitsize  = address length in bits
  813.  *
  814.  * Return true if no errors.
  815.  * If there is error, may trash the address.
  816.  */
  817. static BOOL 
  818. GetBitAddress(UBYTE *addr, UBYTE *string, LONG bitsize)
  819. {
  820.   LONG bitsperbyte; UWORD next; UWORD chars;
  821.   UBYTE c;
  822.  
  823.   memset(addr, 0, (bitsize + 7) >> 3);
  824.  
  825.   while (bitsize > 0) {
  826.     bitsperbyte = bitsize < 8 ? bitsize : 8;
  827.     chars = next = 0;
  828.     while ((c = *string - '0') <= 9 
  829.       || (c = c - 'A' + '0' + 10) >= 9 && c < 16  /*ABCDEF*/
  830.       || (c = c - 'a' + 'A') >= 9 && c < 16) /*abcdef*/ {
  831.       chars++; string++;
  832.       next = (next << 4) + c;
  833.       if (next >= 1 << bitsperbyte)
  834.     return FALSE;
  835.     }
  836.     if (!chars)
  837.       return FALSE;
  838.  
  839.     *addr++ = next << (8 - bitsperbyte);
  840.     bitsize -= bitsperbyte;
  841.     if (*string != ':')
  842.       break;
  843.     string++;
  844.   }
  845.   if (bitsize || *string) return FALSE;
  846.   return TRUE;
  847. }
  848.  
  849. /*
  850.  * Print Hardware Address
  851.  */
  852. static char *
  853. SanaSprintf(register char *ap, int len)
  854. {
  855.   const char *digits = "0123456789ABCDEF";
  856.   register i;
  857.   static char addrbuf[17*3];
  858.   register unsigned char *cp = addrbuf;
  859.  
  860.   for (i = 0; i < len; ) {
  861.     *cp++ = digits[*ap >> 4];
  862.     *cp++ = digits[*ap++ & 0xf];
  863.     i++;
  864.     if (i < len) 
  865.       *cp++ = ':';
  866.   }
  867.   *cp = 0;
  868.   return (addrbuf);
  869. }
  870.  
  871. void ASM stuffchar(REG(d0) char ch, REG(a3) struct CSource * sc)
  872. {
  873.   if (sc->CS_CurChr < sc->CS_Length 
  874.       && (sc->CS_Buffer[sc->CS_CurChr] = ch))
  875.     sc->CS_CurChr++;
  876. }
  877.  
  878. static ULONG
  879. csprintf(struct CSource *buf, const char *fmt, ...)
  880. {
  881.   ULONG start = buf->CS_CurChr;
  882.   va_list ap;
  883.  
  884.   va_start(ap, fmt);
  885.   RawDoFmt((STRPTR)fmt, ap, stuffchar, buf);
  886.   va_end(ap);
  887.  
  888.   buf->CS_Buffer[buf->CS_CurChr] = '\0';
  889.   return buf->CS_CurChr - start;
  890. }
  891.  
  892.